package com.zhentao.service;

import com.zhentao.dto.QueryConditionDto;
import com.zhentao.dto.SummaryQueryResultDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ARIMA时间序列预测服务
 * 实现基于历史数据的趋势预测和异常检测
 */
@Service
public class ArimaPredictionService {

    @Autowired
    private AnomalyDetectionService anomalyDetectionService;

    /**
     * 总金额预测 - 基于ARIMA模型
     */
    public Map<String, Object> predictTotalAmount(QueryConditionDto condition, int forecastPeriods) {
        try {
            // 获取历史数据
            List<SummaryQueryResultDto> historicalData = getHistoricalData(condition);
            
            // 数据预处理
            List<Double> timeSeries = preprocessData(historicalData);
            
            // 执行ARIMA预测
            List<Double> predictions = performArimaPrediction(timeSeries, forecastPeriods);
            
            // 计算预测指标
            Map<String, Object> metrics = calculatePredictionMetrics(timeSeries, predictions);
            
            // 异常检测
            double sensitivity = 2.0; // 异常检测敏感度
            Map<String, Object> anomalyResults = anomalyDetectionService.comprehensiveAnomalyDetection(
                timeSeries, predictions, sensitivity);
            
            // 构建结果
            Map<String, Object> result = new HashMap<>();
            result.put("historicalData", timeSeries);
            result.put("predictions", predictions);
            result.put("forecastPeriods", forecastPeriods);
            result.put("status", "completed");
            result.put("message", "ARIMA预测完成");
            result.put("timestamp", System.currentTimeMillis());
            result.put("formattedTimestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
            // 添加异常检测结果
            result.putAll(anomalyResults);
            
            return result;
            
        } catch (Exception e) {
            Map<String, Object> result = new HashMap<>();
            result.put("status", "error");
            result.put("message", "预测失败: " + e.getMessage());
            result.put("timestamp", System.currentTimeMillis());
            result.put("formattedTimestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            return result;
        }
    }

    /**
     * 分组预测 - 按不同维度进行预测
     */
    public List<Map<String, Object>> predictGrouped(QueryConditionDto condition, int forecastPeriods) {
        try {
            List<Map<String, Object>> results = new ArrayList<>();
            
            // 获取数据（目前为历史数据的集合）
            List<SummaryQueryResultDto> groupedData = getHistoricalData(condition);
            
            // 直接对整体数据进行预测，避免依赖 getDimensionValues()
            List<Double> timeSeries = preprocessData(groupedData);
            List<Double> predictions = performArimaPrediction(timeSeries, forecastPeriods);
            
            Map<String, Object> groupResult = new HashMap<>();
            groupResult.put("dimensionValue", "全部");
            groupResult.put("historicalData", timeSeries);
            groupResult.put("predictions", predictions);
            groupResult.put("forecastPeriods", forecastPeriods);
            groupResult.put("status", "completed");
            
            results.add(groupResult);
            
            return results;
            
        } catch (Exception e) {
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("status", "error");
            errorResult.put("message", "分组预测失败: " + e.getMessage());
            return Arrays.asList(errorResult);
        }
    }

    /**
     * 获取历史数据
     */
    private List<SummaryQueryResultDto> getHistoricalData(QueryConditionDto condition) {
        // 这里应该调用数据查询服务获取历史数据
        // 暂时返回模拟数据用于演示
        return generateMockHistoricalData();
    }

    /**
     * 数据预处理 - 转换为时间序列格式
     */
    private List<Double> preprocessData(List<SummaryQueryResultDto> data) {
        return data.stream()
                .map(item -> {
                    // 优先使用人民币金额，如果没有则使用美元金额
                    if (item.getAmountCny() != null) {
                        return item.getAmountCny().doubleValue();
                    } else if (item.getAmountUsd() != null) {
                        return item.getAmountUsd().doubleValue() * 7.2; // 转换为人民币
                    }
                    return 0.0;
                })
                .filter(amount -> amount > 0)
                .collect(Collectors.toList());
    }

    /**
     * 执行ARIMA预测
     */
    private List<Double> performArimaPrediction(List<Double> timeSeries, int forecastPeriods) {
        if (timeSeries.isEmpty()) {
            return generateMockPredictions(forecastPeriods);
        }
        
        // 简化的ARIMA预测逻辑
        List<Double> predictions = new ArrayList<>();
        double lastValue = timeSeries.get(timeSeries.size() - 1);
        double trend = calculateLinearSlope(timeSeries);
        
        for (int i = 1; i <= forecastPeriods; i++) {
            // 基于趋势和随机波动的预测
            double prediction = lastValue + trend * i + (Math.random() - 0.5) * lastValue * 0.1;
            predictions.add(Math.max(prediction, 0)); // 确保预测值非负
        }
        
        return predictions;
    }
    
    /**
     * 生成模拟预测数据
     */
    private List<Double> generateMockPredictions(int forecastPeriods) {
        List<Double> predictions = new ArrayList<>();
        double baseAmount = 1000000; // 基础金额
        
        for (int i = 1; i <= forecastPeriods; i++) {
            // 模拟上升趋势
            double trend = 50000 * i;
            double seasonality = 200000 * Math.sin(2 * Math.PI * i / 12);
            double random = (Math.random() - 0.5) * 100000;
            
            double prediction = baseAmount + trend + seasonality + random;
            predictions.add(Math.max(prediction, 0));
        }
        
        return predictions;
    }
    
    /**
     * 计算线性斜率（趋势）
     */
    private double calculateLinearSlope(List<Double> data) {
        if (data.size() < 2) return 0.0;
        
        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
        int n = data.size();
        
        for (int i = 0; i < n; i++) {
            double x = i;
            double y = data.get(i);
            sumX += x;
            sumY += y;
            sumXY += x * y;
            sumX2 += x * x;
        }
        
        double slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
        return slope;
    }

    /**
     * 计算预测指标
     */
    private Map<String, Object> calculatePredictionMetrics(List<Double> historical, List<Double> predictions) {
        Map<String, Object> metrics = new HashMap<>();
        
        if (historical.isEmpty() || predictions.isEmpty()) {
            metrics.put("mape", 0.0);
            metrics.put("rmse", 0.0);
            metrics.put("trend", "stable");
            return metrics;
        }
        
        // 计算趋势
        String trend = calculateTrendDirection(historical);
        metrics.put("trend", trend);
        
        // 计算预测精度（如果有足够的历史数据）
        if (historical.size() >= 2) {
            double mape = calculateMAPE(historical, predictions);
            double rmse = calculateRMSE(historical, predictions);
            metrics.put("mape", mape);
            metrics.put("rmse", rmse);
        }
        
        return metrics;
    }

    /**
     * 计算趋势方向
     */
    private String calculateTrendDirection(List<Double> data) {
        if (data.size() < 2) return "stable";
        
        double firstHalf = 0, secondHalf = 0;
        int mid = data.size() / 2;
        
        for (int i = 0; i < mid; i++) {
            firstHalf += data.get(i);
        }
        for (int i = mid; i < data.size(); i++) {
            secondHalf += data.get(i);
        }
        
        double avgFirst = firstHalf / mid;
        double avgSecond = secondHalf / (data.size() - mid);
        
        if (avgSecond > avgFirst * 1.1) return "increasing";
        if (avgSecond < avgFirst * 0.9) return "decreasing";
        return "stable";
    }

    /**
     * 计算平均绝对百分比误差 (MAPE)
     */
    private double calculateMAPE(List<Double> actual, List<Double> predicted) {
        if (actual.size() != predicted.size() || actual.isEmpty()) return 0.0;
        
        double sum = 0;
        int count = 0;
        
        for (int i = 0; i < actual.size(); i++) {
            if (actual.get(i) != 0) {
                sum += Math.abs((actual.get(i) - predicted.get(i)) / actual.get(i));
                count++;
            }
        }
        
        return count > 0 ? (sum / count) * 100 : 0.0;
    }

    /**
     * 计算均方根误差 (RMSE)
     */
    private double calculateRMSE(List<Double> actual, List<Double> predicted) {
        if (actual.size() != predicted.size() || actual.isEmpty()) return 0.0;
        
        double sum = 0;
        
        for (int i = 0; i < actual.size(); i++) {
            double diff = actual.get(i) - predicted.get(i);
            sum += diff * diff;
        }
        
        return Math.sqrt(sum / actual.size());
    }

    /**
     * 生成模拟历史数据用于演示
     */
    private List<SummaryQueryResultDto> generateMockHistoricalData() {
        List<SummaryQueryResultDto> mockData = new ArrayList<>();
        
        // 生成12个月的模拟数据
        for (int i = 0; i < 12; i++) {
            SummaryQueryResultDto item = new SummaryQueryResultDto();
            
            // 模拟金额数据，包含趋势和季节性
            double baseAmount = 1000000; // 基础金额
            double trend = 50000 * i; // 上升趋势
            double seasonality = 200000 * Math.sin(2 * Math.PI * i / 12); // 季节性波动
            double random = (Math.random() - 0.5) * 100000; // 随机波动
            
            double amount = baseAmount + trend + seasonality + random;
            
            item.setAmountCny(java.math.BigDecimal.valueOf(amount));
            item.setAmountUsd(java.math.BigDecimal.valueOf(amount / 7.2));
            // 本模块DTO的 goodsQuantity 为 BigDecimal 类型
            item.setGoodsQuantity(java.math.BigDecimal.valueOf(1000L + i * 50));
            item.setDeclareCount(Long.valueOf(100L + i * 5));
            item.setRecordCount(Long.valueOf(150L + i * 8));
            
            // 设置分组/时间信息（本模块DTO不包含 dimensionValues 字段）
            item.setGroupKey("month");
            item.setGroupValue(String.valueOf(i + 1));
            item.setTimePeriod("monthly");
            item.setTimeValue(String.valueOf(i + 1));
            
            mockData.add(item);
        }
        
        return mockData;
    }

    /**
     * 生成前端表格需要的预测数据格式
     */
    public List<Map<String, Object>> generatePredictionTableData(int forecastPeriods) {
        List<Map<String, Object>> tableData = new ArrayList<>();
        
        for (int i = 1; i <= forecastPeriods; i++) {
            Map<String, Object> row = new HashMap<>();
            
            // 预测周期
            row.put("预测周期", "第" + i + "期");
            
            // 预测金额（基于趋势和季节性）
            double baseAmount = 1000000;
            double trend = 50000 * i;
            double seasonality = 200000 * Math.sin(2 * Math.PI * i / 12);
            double random = (Math.random() - 0.5) * 100000;
            double predictedAmount = baseAmount + trend + seasonality + random;
            row.put("预测金额", Math.max(predictedAmount, 0));
            
            // 置信度（基于预测期数，越远置信度越低）
            double confidence = Math.max(0.8 - (i - 1) * 0.05, 0.3);
            row.put("置信度", confidence);
            
            // 趋势判断
            String trendDirection;
            if (trend > 0) {
                trendDirection = trend > 100000 ? "上升" : "平稳";
            } else {
                trendDirection = "下降";
            }
            row.put("趋势", trendDirection);
            
            tableData.add(row);
        }
        
        return tableData;
    }
} 

 